package com.ruoyi.workflow.service.impl;

import com.ruoyi.activity.service.IFlowService;
import com.ruoyi.common.core.domain.AjaxResult;
import com.ruoyi.common.core.domain.entity.SysUser;
import com.ruoyi.common.utils.SecurityUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.system.domain.CompanyInfo;
import com.ruoyi.system.service.ICompanyInfoService;
import com.ruoyi.system.service.impl.SysUserServiceImpl;
import com.ruoyi.utils.BusinessService;
import com.ruoyi.utils.ProcessService;
import com.ruoyi.workflow.constants.*;
import com.ruoyi.workflow.domain.ApprovalRecords;
import com.ruoyi.workflow.domain.CompanyApply;
import com.ruoyi.workflow.domain.Message;
import com.ruoyi.workflow.dto.*;
import com.ruoyi.workflow.mapper.CompanyApplyMapper;
import com.ruoyi.workflow.myenum.MessageType;
import com.ruoyi.workflow.service.IApprovalRecordsService;
import com.ruoyi.workflow.service.ICompanyApplyService;
import com.ruoyi.workflow.service.UserMessageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;

import static com.ruoyi.workflow.constants.TaskType.COMPLETED;
import static com.ruoyi.workflow.constants.TaskType.UNHANDLED;

/**
 * 单位注册审批记录Service业务层处理
 *
 * @author 周志雄
 * @date 2024-03-04
 */
@Slf4j
@Service
public class CompanyApplyServiceImpl implements ICompanyApplyService {
    @Resource
    private UserMessageService userMessageService;
    @Resource
    private CompanyApplyMapper companyApplyMapper;
    @Resource
    private SysUserServiceImpl sysUserService;
    @Resource
    private ProcessService processService;
    @Resource
    private ICompanyInfoService companyInfoService;
    @Resource
    private IApprovalRecordsService approvalRecordsService;
    @Resource
    private BusinessService businessService;

    /**
     * 开始一个单位审批流程
     *
     * @param companyId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<String> startFlow(String companyId) throws Exception {
        // 先查询单位的基本信息
        Long userId = SecurityUtils.getUserId();
        CompanyInfo companyInfo = companyInfoService.selectCompanyInfoById(Long.valueOf(companyId));
        // 首先设置流程发起的参数并组装、然后写入业务的申请表
        CompanyApply companyApply = new CompanyApply();
        companyApply.setApplyUserId(String.valueOf(userId));
        companyApply.setCompanyId(String.valueOf(companyId));
        companyApply.setApplyTime(new Date());
        companyApply.setApplicationFileUrl(companyInfo.getRelatedFilePath());
        companyApply.setApplicationFilesUrl(companyInfo.getRelatedFilesPath());
        companyApply.setApplicationImageUrl(companyInfo.getBusinessLicensePath());

        // 设置默认初始审批状态为审核中
        companyApply.setApplicationStatus(ApplyStatusConstant.UNDER_REVIEW);

        // 写入业务数据并获取 BusinessKey
        companyApplyMapper.insert(companyApply);
        Long businessKey = Long.valueOf(companyApply.getApplyId());
        processService.startProcess(ProcessTypeConstant.COMPANY_APPLY, String.valueOf(businessKey), null);
        return AjaxResult.success("发起单位审批成功");
    }

    /**
     * 开始一个单位审批流程
     *
     * @param companyId
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<String> startFlow(String companyId,String userId) throws Exception {
        // 先查询单位的基本信息
        CompanyInfo companyInfo = companyInfoService.selectCompanyInfoById(Long.valueOf(companyId));
        // 首先设置流程发起的参数并组装、然后写入业务的申请表
        CompanyApply companyApply = new CompanyApply();
        companyApply.setApplyUserId(String.valueOf(userId));
        companyApply.setCompanyId(String.valueOf(companyId));
        companyApply.setApplyTime(new Date());
        companyApply.setApplicationFileUrl(companyInfo.getRelatedFilePath());
        companyApply.setApplicationFilesUrl(companyInfo.getRelatedFilesPath());
        companyApply.setApplicationImageUrl(companyInfo.getBusinessLicensePath());

        // 设置默认初始审批状态为审核中
        companyApply.setApplicationStatus(ApplyStatusConstant.UNDER_REVIEW);

        // 写入业务数据并获取 BusinessKey
        companyApplyMapper.insert(companyApply);
        Long businessKey = Long.valueOf(companyApply.getApplyId());
        processService.startProcess(ProcessTypeConstant.COMPANY_APPLY, String.valueOf(businessKey), null);
        return AjaxResult.success("发起单位审批成功");
    }

    /**
     * 完成单位审批操作
     *
     * @param taskCompleteDto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public AjaxResult<String> completeTask(TaskCompleteDto taskCompleteDto) {
        // 获取流程实例ID
        String processId = businessService.getProcessId(ProcessTypeConstant.COMPANY_APPLY, taskCompleteDto.getApplyId());
        // 获取待办任务的节点名称、审批人、任务ID对应的Map列表
        List<Map<String, String>> nodeNameAndAssigneeList = processService.getNodeNameAssigneeAndTaskIdByProcessInstanceId(processId);
        // 获取当前用户ID
        String currentUserId = SecurityUtils.getLoginUser().getUserId().toString();
        TaskApprovalContext context = findApprovalContext(nodeNameAndAssigneeList, currentUserId);
        context.setProcessId(processId);
        if (!context.isApprover) {
            return AjaxResult.success("当前用户不是该节点的审批人");
        }
        // 无论是否同意都需要新增一条审批记录
        createAndStoreApprovalRecords(taskCompleteDto, context);
        return handleTaskCompletion(taskCompleteDto, context);
    }

    /**
     * 查询当前用户是否处于待办任务列表中的一位
     *
     * @param nodeNameAndAssigneeList
     * @param currentUserId
     * @return
     */
    private TaskApprovalContext findApprovalContext(List<Map<String, String>> nodeNameAndAssigneeList, String currentUserId) {
        for (Map<String, String> nodeNameAndAssignee : nodeNameAndAssigneeList) {
            if (nodeNameAndAssignee.get("assignee").equals(currentUserId)) {
                return new TaskApprovalContext(true, nodeNameAndAssignee.get("nodeName"), nodeNameAndAssignee.get("assignee"), nodeNameAndAssignee.get("taskId"));
            }
        }
        return new TaskApprovalContext(false, "", "", "");
    }

    /**
     * 新增审批记录
     *
     * @param taskCompleteDto
     * @param context
     */
    private void createAndStoreApprovalRecords(TaskCompleteDto taskCompleteDto, TaskApprovalContext context) {
        ApprovalRecords approvalRecords = new ApprovalRecords();
        approvalRecords.setBusinessKey(Long.valueOf(taskCompleteDto.getApplyId()));
        approvalRecords.setBusinessType(ProcessTypeConstant.COMPANY_APPLY);
        approvalRecords.setProcessId(context.getProcessId());
        approvalRecords.setProcessName(ProcessTypeConstant.COMPANY_APPLY_NAME);
        approvalRecords.setApprovalStatus(Long.valueOf(taskCompleteDto.getOutcome()));
        approvalRecords.setApprovalFileUrl(taskCompleteDto.getApprovalFileUrl());
        approvalRecords.setApprovalComment(taskCompleteDto.getComment());
        approvalRecords.setApprovalImageUrl(taskCompleteDto.getApprovalImageUrl());
        approvalRecords.setApprovalNodeName(context.matchedNodeName);
        approvalRecords.setApproverId(context.matchedAssignee);
        approvalRecords.setApprovalTime(new Date());
        System.out.println(approvalRecordsService);
        approvalRecordsService.insertApprovalRecords(approvalRecords);
    }

    /**
     * 处理任务完成
     *
     * @param taskCompleteDto
     * @param context
     * @return
     */
    private AjaxResult<String> handleTaskCompletion(TaskCompleteDto taskCompleteDto, TaskApprovalContext context) {
        if (taskCompleteDto.getOutcome().equals(ApprovalTypeConstant.APPROVE)) {
            // 处理同意的情况
            return handleApproval(taskCompleteDto, context);
        } else {
            // 处理拒绝的情况
            return handleRejection(taskCompleteDto, context);
        }
    }

    /**
     * 拒绝则直接终止流程的进行
     *
     * @param taskCompleteDto
     * @param context
     * @return
     */
    private AjaxResult<String> handleRejection(TaskCompleteDto taskCompleteDto, TaskApprovalContext context) {
        processService.terminateProcessInstance(context.processId);
        if(taskCompleteDto.getOutcome()==2){
            updateCompanyApplyStatus(taskCompleteDto.getApplyId(), ApplyStatusConstant.BACK);
        }else if(taskCompleteDto.getOutcome()==3){
            updateCompanyApplyStatus(taskCompleteDto.getApplyId(), ApplyStatusConstant.MODIFY_APPROVE);
        }else if(taskCompleteDto.getOutcome()==4){
            updateCompanyApplyStatus(taskCompleteDto.getApplyId(), ApplyStatusConstant.REJECTED);
        }
        // 发送消息
        sendMess(taskCompleteDto,"审批不通过");
        return AjaxResult.success("流程已终止并标记为拒绝");
    }

    /**
     * 处理任务同意的情况
     *
     * @param taskCompleteDto
     * @param context
     * @return
     */
    private AjaxResult<String> handleApproval(TaskCompleteDto taskCompleteDto, TaskApprovalContext context) {
        // 如果参数中含有人员列表，则完成任务并加签
        if (taskCompleteDto.getApprovalUserIds() != null) {
            // 创建一个HashMap来存放变量
            Map<String, Object> variables = new HashMap<>();
            // 向变量集添加addSignature变量
            variables.put("addSignature", true);
            variables.put("approvalUserIds", taskCompleteDto.getApprovalUserIds());
            processService.completeTask(context.matchedTaskId, variables);
            return AjaxResult.success("加签成功");
        } else {
            Map<String, Object> variables = new HashMap<>();
            String applyId = taskCompleteDto.getApplyId();
            String processId = businessService.getProcessId(ProcessTypeConstant.COMPANY_APPLY, applyId);
            boolean nextNodeCounterSignatureGateway = processService.isNextNodeCounterSignatureGateway(processId);
            if (nextNodeCounterSignatureGateway == true) {
                // 创建一个HashMap来存放变量
                variables.put("addSignature", false);
            }
            processService.completeTask(context.matchedTaskId, variables);
            if (processService.isProcessInstanceEnded(context.processId)) {
                // 流程完结的话则更新单位审批申请的状态为完成
                updateCompanyApplyStatus(taskCompleteDto.getApplyId(), ApplyStatusConstant.COMPLETED);
                // 流程完结的话则更新单位基本信息表的注册状态为成功
                updateCompanyRegistrationInfo(taskCompleteDto.getApplyId());
                // 发送消息
                sendMess(taskCompleteDto,"审批通过");
            }
            return AjaxResult.success("完成单位审批操作");
        }
    }

    private void sendMess(TaskCompleteDto taskCompleteDto, String note) {
        // 通过业务审批ID找到发起人
        CompanyApply companyApply = companyApplyMapper.selectInfoById(taskCompleteDto.getApplyId());
        String companyId = companyApply.getCompanyId();
        // 根据单位ID得到单位信息
        CompanyInfo companyInfo = companyInfoService.selectCompanyInfoById(Long.valueOf(companyId));
        // 新建消息对象
        Message message = new Message();
        // 接受消息的人
        message.setUserId(companyApply.getApplyUserId());
        // 消息类型
        message.setMessageType(MessageType.UNIT_REGISTRATION_RESULT_NOTIFICATION);
        // 创建时间
        message.setCreateTime(new Date());
        // 消息内容
        message.setMessageContent(companyInfo.getCompanyName() + note);
        message.setDetailUrl("详情页面路径");
        userMessageService.sendMessage(message);
    }

    /**
     * 更新单位注册申请状态
     *
     * @param applyId
     * @param status
     */
    private void updateCompanyApplyStatus(String applyId, Integer status) {
        CompanyApply companyApply = new CompanyApply();
        companyApply.setApplyId(Integer.valueOf(applyId));
        companyApply.setApplicationStatus(status);
        companyApply.setLastTime(new Date());
        companyApplyMapper.updateCompanyApply(companyApply);
    }

    /**
     * 更新单位注册信息表的注册状态为为成功
     *
     * @param applyId
     */
    private void updateCompanyRegistrationInfo(String applyId) {
        // 先获取单位ID
        String companyId = companyApplyMapper.selectInfoById(applyId).getCompanyId();
        // 获取单位信息
        CompanyInfo companyInfo = companyInfoService.selectCompanyInfoById(Long.valueOf(companyId));
        companyInfo.setRegisterStatus("true");
        companyInfoService.updateCompanyInfo(companyInfo);
    }


    /**
     * 根据任务类型查询任务列表
     *
     * @param companyApplySearchDto 查询条件
     * @return 任务列表
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public List<CompanyApplyResDto> selectTaskListByType(CompanyApplySearchDto companyApplySearchDto) {
        return selectListByType(companyApplySearchDto);
    }

    /**
     * 根据类型去查询返回数据列表
     *
     * @param companyApplySearchDto
     * @return
     */
    private List<CompanyApplyResDto> selectListByType(CompanyApplySearchDto companyApplySearchDto) {
        // 拿到审核的筛选状态（1待我处理、2我已处理、3全部）
        Integer approvalStatus = companyApplySearchDto.getApprovalStatus();
        Long userId = SecurityUtils.getLoginUser().getUserId();
        // 获取流程实例ID列表
        List<String> processInstanceIds = getProcessInstanceIds(approvalStatus, userId);
        List<String> businessKeys = processService.getBusinessKeysByProcessInstanceIds(processInstanceIds);

        if (StringUtils.isNotEmpty(businessKeys)) {
            return processBusinessKeys(businessKeys, companyApplySearchDto, approvalStatus, userId);
        }
        return new ArrayList<>();
    }

    /**
     * 根据条件去获取流程实例列表
     *
     * @param approvalStatus
     * @param userId
     * @return
     */
    private List<String> getProcessInstanceIds(Integer approvalStatus, Long userId) {
        if (approvalStatus == UNHANDLED) {
            return businessService.getActiveProcessInstanceIdsByUserId(ProcessTypeConstant.COMPANY_APPLY, String.valueOf(userId));
        } else if (approvalStatus == COMPLETED) {
            return businessService.getCompletedProcessInstanceIdsByUserId(ProcessTypeConstant.COMPANY_APPLY, String.valueOf(userId));
        } else {
            return businessService.getAllProcessInstanceIds(ProcessTypeConstant.COMPANY_APPLY);
        }
    }

    /**
     * 处理业务键
     *
     * @param businessKeys
     * @param searchDto
     * @param approvalStatus
     * @param userId
     * @return
     */
    private List<CompanyApplyResDto> processBusinessKeys(List<String> businessKeys, CompanyApplySearchDto searchDto, Integer approvalStatus, Long userId) {
        List<CompanyApplyResDto> results = new ArrayList<>();
        List<CompanyApplyResDto> companyApplyResDtoList = companyApplyMapper.selectByBusinessKeyList(businessKeys, searchDto);
        if (StringUtils.isNotNull(companyApplyResDtoList)) {
            for (CompanyApplyResDto originalDto : companyApplyResDtoList) {
                originalDto.setApprovalStatus(ApplyStatusConstant.getApplyStatus(Integer.valueOf(originalDto.getApprovalStatus())));
                if (ApplyStatusConstant.UNDER_REVIEW_STR.equals(originalDto.getApprovalStatus())) {
                    expandUnderReviewEntries(originalDto, results, approvalStatus, userId);
                } else {
                    results.add(originalDto);
                }
            }
        }
        return results;
    }

    /**
     * 展开审核中的条目
     *
     * @param originalDto
     * @param results
     * @param approvalStatus
     * @param userId
     */
    private void expandUnderReviewEntries(CompanyApplyResDto originalDto, List<CompanyApplyResDto> results, Integer approvalStatus, Long userId) {
        Map<String, String> taskDetails = processService.getActiveTaskStringDetails(ProcessTypeConstant.COMPANY_APPLY, originalDto.getApplyId());
        String[] nodeNames = taskDetails.get("nodeNames").split(",");
        String[] assignees = taskDetails.get("assignees").split(",");

        for (int i = 0; i < nodeNames.length; i++) {
            String assigneeId = assignees[i].trim();
            if (approvalStatus.equals(UNHANDLED) && !assigneeId.equals(String.valueOf(userId))) {
                continue;
            }

            if(nodeNames[i]!="" && assignees[i]!="") {
                CompanyApplyResDto splitDto = createSplitDto(originalDto, nodeNames[i], assigneeId);
                results.add(splitDto);
            }
        }
    }

    /**
     * 创建拆分的DTO
     *
     * @param originalDto
     * @param nodeName
     * @param assigneeId
     * @return
     */
    private CompanyApplyResDto createSplitDto(CompanyApplyResDto originalDto, String nodeName, String assigneeId) {
        CompanyApplyResDto splitDto = new CompanyApplyResDto();
        splitDto.setApplyId(originalDto.getApplyId());
        splitDto.setCompanyName(originalDto.getCompanyName());
        splitDto.setUnifiedSocialCreditCode(originalDto.getUnifiedSocialCreditCode());
        splitDto.setLegalRepresentative(originalDto.getLegalRepresentative());
        splitDto.setLegalRepresentativePhone(originalDto.getLegalRepresentativePhone());
        splitDto.setApprovalStatus(originalDto.getApprovalStatus());
        splitDto.setSubmissionTime(originalDto.getSubmissionTime());
        splitDto.setCurrentApprovalNodeName(nodeName);

        SysUser sysUser = sysUserService.selectUserById(Long.valueOf(assigneeId));
        if (StringUtils.isNotNull(sysUser)) {
            splitDto.setCurrentApproverId(String.valueOf(sysUser.getUserId()));
            splitDto.setCurrentApprover(sysUser.getNickName());
        }
        return splitDto;
    }

    @Override
    public AjaxResult<String> rollback(String applyId) {
        // 先查询流程是否已经有对应的审判数据，如果有则不允许撤销
        ApprovalRecords approvalRecords = approvalRecordsService.selectByApplyId(applyId);
        if (approvalRecords != null) {
            return AjaxResult.success("已经开始了审批流程，无法撤回");
        }
        // 根据业务类型和 businessKey 获取对应的流程实例ID
        String processId = businessService.getProcessId(ProcessTypeConstant.COMPANY_APPLY, applyId);
        processService.terminateProcessInstance(processId);

        // 需要更新业务申请表
        CompanyApply companyApply = new CompanyApply();
        companyApply.setApplyId(Integer.valueOf(applyId));
        companyApply.setLastTime(new Date());
        companyApply.setApplicationStatus(ApplyStatusConstant.CANCEL);
        companyApplyMapper.updateCompanyApply(companyApply);
        return AjaxResult.success("撤销申请成功");
    }

    /**
     * 查询进入详情页
     *
     * @param id
     * @return
     */
    @Override
    public CompanyApplyInfoDto selectInfoById(String id) {
        // 根据 BusinessKey 来获取业务数据
        CompanyApplyInfoDto companyApplyInfoDto = companyApplyMapper.queryBasicInfo(id);
        String processId = businessService.getProcessId(ProcessTypeConstant.COMPANY_APPLY, id);

        // 判断流程是否结束
        boolean processInstanceEnded = processService.isProcessInstanceEnded(processId);
        if (!processInstanceEnded) {
            // 流程没结束则渲染动态节点
            byte[] processInstanceImage = processService.displayFlowCurrPic(processId);
            companyApplyInfoDto.setBase64(processInstanceImage);
            // 流程没结束则判断下一个节点是不是加签节点，是的话给一个标识
            boolean nextNodeCounterSignatureGateway = processService.isNextNodeCounterSignatureGateway(processId);
            companyApplyInfoDto.setIsAddSign(nextNodeCounterSignatureGateway);
        }

        // 设置审批状态为字符串
        companyApplyInfoDto.setApplyStatus(ApplyStatusConstant.getApplyStatus(Integer.valueOf(companyApplyInfoDto.getApplyStatus())));
        // 根据业务类型和 BusinessKey 去获取审批数据
        List<ApprovalRecordsDto> approvalRecordsDtos = approvalRecordsService.selectByCondition(ProcessTypeConstant.COMPANY_APPLY, companyApplyInfoDto.getApplyId());
        if (StringUtils.isNotNull(approvalRecordsDtos)) {
            approvalRecordsDtos.forEach(approvalRecordsDto -> {
                // 修改每个人的审批意见为字符串
                approvalRecordsDto.setApprovalStatus(ApprovalTypeConstant.getApprovalStatus(Integer.valueOf(approvalRecordsDto.getApprovalStatus())));
            });
        }
        companyApplyInfoDto.setApprovalList(approvalRecordsDtos);
        return companyApplyInfoDto;
    }
}
